package fun.qu_an.velocity.whitelist.command;

import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.velocitypowered.api.command.BrigadierCommand;
import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.event.permission.PermissionsSetupEvent;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.proxy.ConsoleCommandSource;
import com.velocitypowered.api.proxy.Player;
import fun.qu_an.lib.basic.util.result.Result;
import fun.qu_an.velocity.whitelist.VelocityWhitelist;
import fun.qu_an.velocity.whitelist.whitelist.WhitelistManagements;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;

import java.util.Set;
import java.util.concurrent.CompletableFuture;

import static fun.qu_an.lib.minecraft.vanilla.util.CommandUtils.buildSuggestions;
import static fun.qu_an.velocity.whitelist.config.VelocityWhitelistConfig.CONFIG;
import static fun.qu_an.velocity.whitelist.translate.Translates.*;
import static fun.qu_an.velocity.whitelist.util.Utils.PLAYER_UTIL;
import static fun.qu_an.velocity.whitelist.util.Utils.PROXY_SERVER;

public class VWhitelistCommand {
	/**
	 * 白名单命令使用权的权限组ID
	 */
	public static final String PERMISSION_WHITELIST_USE = "qu_an.whitelist.use";
	/**
	 * 白名单权限管理权的权限组ID
	 */
	public static final String PERMISSION_WHITELIST_ADMIN = "qu_an.whitelist.admin";
	/**
	 * 用于编辑权限时的命令提示
	 */
	private static final Set<String> PERMISSIONS = Set.of("use", "admin");
	private static final Logger logger = VelocityWhitelist.getLogger();

	/**
	 * 注册白名单命令
	 */
	public static void register() {
		CommandManager commandManager = PROXY_SERVER.getCommandManager();
		commandManager.register(new BrigadierCommand(buildCommand(LiteralArgumentBuilder.<CommandSource>literal("whitelist")
			.requires(source -> source instanceof ConsoleCommandSource))));
		commandManager.register(new BrigadierCommand(buildCommand(LiteralArgumentBuilder.literal("vwhitelist"))));
	}

	private static LiteralArgumentBuilder<CommandSource> buildCommand(LiteralArgumentBuilder<CommandSource> whitelist) {
		return whitelist
			// 列出所有白名单玩家
			.then(LiteralArgumentBuilder
				.<CommandSource>literal("list")
				.executes(VWhitelistCommand::list))
			// 重载白名单
			.then(LiteralArgumentBuilder
				.<CommandSource>literal("load")
				.requires(source -> source.hasPermission(PERMISSION_WHITELIST_USE))
				.executes(VWhitelistCommand::reload))
			// 开启白名单
			.then(LiteralArgumentBuilder
				.<CommandSource>literal("on")
				.requires(source -> source.hasPermission(PERMISSION_WHITELIST_USE))
				.executes(VWhitelistCommand::on))
			// 关闭白名单
			.then(LiteralArgumentBuilder
				.<CommandSource>literal("off")
				.requires(source -> source.hasPermission(PERMISSION_WHITELIST_USE))
				.executes(VWhitelistCommand::off))
			// 添加白名单
			.then(LiteralArgumentBuilder
				.<CommandSource>literal("add")
				.requires(source -> source.hasPermission(PERMISSION_WHITELIST_USE))
				// 玩家名
				.then(RequiredArgumentBuilder
					.<CommandSource, String>argument("player", StringArgumentType.greedyString())
					.suggests((context, builder) -> buildSuggestions(builder, PLAYER_UTIL.getPlayerNames()))
					.executes(VWhitelistCommand::add)))
			// 移除白名单
			.then(LiteralArgumentBuilder
				.<CommandSource>literal("remove")
				.requires(source -> source.hasPermission(PERMISSION_WHITELIST_USE))
				// 玩家名
				.then(RequiredArgumentBuilder
					.<CommandSource, String>argument("player", StringArgumentType.greedyString())
					.suggests((context, builder) -> buildSuggestions(builder, WhitelistManagements.list()))
					.executes(VWhitelistCommand::remove)))
			// 编辑权限
			.then(LiteralArgumentBuilder
				.<CommandSource>literal("permission")
				.requires(source -> source.hasPermission(PERMISSION_WHITELIST_ADMIN))
				// 添加权限
				.then(LiteralArgumentBuilder
					.<CommandSource>literal("add")
					// 玩家名
					.then(RequiredArgumentBuilder
						.<CommandSource, String>argument("player", StringArgumentType.word())
						.suggests((context, builder) -> suggestAllPossiblePlayers(builder))
						// 权限名
						.then(RequiredArgumentBuilder
							.<CommandSource, String>argument("permission", StringArgumentType.word())
							.suggests((context, builder) -> buildSuggestions(builder, PERMISSIONS))
							.executes(VWhitelistCommand::addPermission))))
				// 移除权限
				.then(LiteralArgumentBuilder.<CommandSource>literal("remove")
					// 玩家名
					.then(RequiredArgumentBuilder
						.<CommandSource, String>argument("player", StringArgumentType.word())
						.suggests((context, builder) -> suggestPermissionPlayers(builder))
						.executes(VWhitelistCommand::removePermission))))
			.then(LiteralArgumentBuilder
				.<CommandSource>literal("test")
				.requires(source -> source.hasPermission(PERMISSION_WHITELIST_USE))
				.then(RequiredArgumentBuilder
					.<CommandSource, String>argument("player", StringArgumentType.word())
					.suggests((context, builder) -> suggestAllPossiblePlayers(builder))
					.executes(VWhitelistCommand::testWhitelist)
				));
	}

	private static int testWhitelist(CommandContext<CommandSource> context) {
		String player = context.getArgument("player", String.class);
		boolean test = WhitelistManagements.test(player);
		context.getSource().sendMessage(Component.text(test));
		return 1;
	}

	/**
	 * 获取所有可能的玩家名
	 */
	private static CompletableFuture<Suggestions> suggestAllPossiblePlayers(SuggestionsBuilder builder) {
		return buildSuggestions(builder,
			WhitelistManagements.list(),
			PLAYER_UTIL.getPlayerNames(),
			CONFIG.usePermissionPlayers(),
			CONFIG.adminPermissionPlayers());
	}

	/**
	 * 获取权限组内的所有玩家名
	 */
	private static CompletableFuture<Suggestions> suggestPermissionPlayers(SuggestionsBuilder builder) {
		return buildSuggestions(builder,
			CONFIG.usePermissionPlayers(),
			CONFIG.adminPermissionPlayers());
	}

	/**
	 * 添加权限
	 */
	private static int addPermission(@NotNull CommandContext<CommandSource> context) {
		String player = context.getArgument("player", String.class);
		String permission = context.getArgument("permission", String.class);
		CommandSource source = context.getSource();
		if (permission.equals("use")) {
			CONFIG.addUsePermission(player);
			PLAYER_UTIL.getPlayerByName(player)
				.ifPresent(player1 ->
					PROXY_SERVER.getEventManager()
						.fire(new PermissionsSetupEvent(
							player1,
							subject -> permission1 -> Tristate.UNDEFINED
						)));
			source.sendMessage(Component.translatable(PERMISSION_ADD_USE, Component.text(player)));
			if (source instanceof Player) {
				logger.info("Added permission {} for player {}.", PERMISSION_WHITELIST_USE, player);
			}
			return 1;
		}
		if (permission.equals("admin")) {
			CONFIG.addAdminPermission(player);
			PLAYER_UTIL.getPlayerByName(player)
				.ifPresent(player1 ->
					PROXY_SERVER.getEventManager()
						.fire(new PermissionsSetupEvent(
							player1,
							subject -> permission1 -> Tristate.UNDEFINED // 此处无需处理
						)));
			source.sendMessage(Component.translatable(PERMISSION_ADD_ADMIN, Component.text(player)));
			if (source instanceof Player) {
				logger.info("Added permission {} for player {}.", PERMISSION_WHITELIST_ADMIN, player);
			}
			return 1;
		}
		source.sendMessage(Component.translatable(PERMISSION_ADD_UNKNOWN, Component.text(permission)));
		return 0;
	}

	/**
	 * 移除权限
	 */
	private static int removePermission(@NotNull CommandContext<CommandSource> context) {
		String player = context.getArgument("player", String.class);
		CommandSource source = context.getSource();
		boolean remove = CONFIG.removePermission(player);
		if (remove){
			PLAYER_UTIL.getPlayerByName(player)
				.ifPresent(player1 ->
					PROXY_SERVER.getEventManager().fire(new PermissionsSetupEvent(
						player1,
						subject ->
							permission ->
								Tristate.UNDEFINED
					)));
			source.sendMessage(Component.translatable(PERMISSION_REMOVE, Component.text(player)));
			if (source instanceof Player) {
				logger.info("Removed permissions for player {}.", player);
			}
			return 1;
		}

		source.sendMessage(Component.translatable(PERMISSION_REMOVE_PLAYER_NOT_EXIST, Component.text(player)));
		return 0;
	}

	/**
	 * 启用白名单
	 */
	private static int on(@NotNull CommandContext<CommandSource> context) {
		CONFIG.enableWhitelist();
		context.getSource().sendMessage(WHITELIST_ON);
		return 0;
	}

	/**
	 * 停用白名单
	 */
	private static int off(@NotNull CommandContext<CommandSource> context) {
		CONFIG.disableWhitelist();
		context.getSource().sendMessage(WHITELIST_OFF);
		return 0;
	}

	/**
	 * 重载白名单
	 */
	private static int reload(@NotNull CommandContext<CommandSource> context) {
		CommandSource source = context.getSource();
		Result result = WhitelistManagements.load();
		if (result.isSucceeded()) {
			source.sendMessage(WHITELIST_RELOAD_SUCCEED);
			if (source instanceof Player) {
				logger.info("Whitelist reload succeed.");
			}
			return 1;
		}
		String message = result.message();
		source.sendMessage(Component.translatable(
			WHITELIST_RELOAD_FAILED,
			Component.text(message) // Exception，不可翻译
		));
		if (source instanceof Player) {
			logger.info("Whitelist reload failed, reason: {}", message);
		}
		return 0;
	}

	/**
	 * 添加白名单
	 */
	private static int add(@NotNull CommandContext<CommandSource> context) {
		String input = context.getArgument("player", String.class);
		CommandSource source = context.getSource();
		Result result = WhitelistManagements.add(input.split(" "));
		if (result.isSucceeded()) {
			source.sendMessage(Component
				.translatable(WHITELIST_ADD_SUCCEED, Component
					.text(result.message()))); // 玩家列表，不可翻译
			if (source instanceof Player) {
				logger.info("Whitelist added: {}.", result.message());
			}
			return 1;
		}
		if (result.isIneffective()) {
			if (result.hasSubResult()) {
				//noinspection ConstantConditions
				source.sendMessage(Component.translatable(WHITELIST_SAVE_FAILED,
					Component.translatable(result.subResult().message())));
				return 0;
			}
			source.sendMessage(Component
				.translatable(WHITELIST_ADD_ALREADY_EXIST, Component
					.text(result.message()))); // 玩家名，不可翻译
			return 0;
		}
		source.sendMessage(Component
			.translatable(WHITELIST_ADD_FAILED, Component
				.translatable(result.message())));
		return 0;
	}

	/**
	 * 移除白名单
	 */
	private static int remove(@NotNull CommandContext<CommandSource> context) {
		String player = context.getArgument("player", String.class);
		CommandSource source = context.getSource();
		Result result = WhitelistManagements.remove(player.split(" "));
		if (result.isSucceeded()) {
			source.sendMessage(Component
				.translatable(WHITELIST_REMOVE_SUCCEED, Component
					.text(result.message()))); // 玩家列表，不可翻译
			if (source instanceof Player) {
				logger.info("Whitelist added: {}.", result.message());
			}
			return 1;
		}
		if (result.isIneffective()) {
			if (result.hasSubResult()) {
				//noinspection ConstantConditions
				source.sendMessage(Component.translatable(WHITELIST_SAVE_FAILED,
					Component.translatable(result.subResult().message())));
				return 0;
			}
			source.sendMessage(Component.translatable(WHITELIST_REMOVE_NOT_FOUND, Component.text(player)));
			return 0;
		}
		source.sendMessage(Component
			.translatable(WHITELIST_REMOVE_FAILED, Component
				.translatable(result.message())));
		return 0;
	}

	/**
	 * 列出所有白名单玩家
	 */
	private static int list(@NotNull CommandContext<CommandSource> context) {
		String players = "[" + String.join(", ", WhitelistManagements.list()) + "]";
		context.getSource().sendMessage(Component.text(players));
		return 0;
	}
}
